import { API_URL, IS_PROD, PUBLIC_PATH } from "./settings/config";
import { getLanguages } from "./settings/lang";
import Vue from "vue";
import axios from "axios";
import { OidcGetUser, removeUser, signinRedirect } from "./oidc";

import { MessageBox, Message, Notification, Tooltip } from "element-ui";
import { disableAllUnloadMessage, getCacheId, showLoading } from "@framework/utilities";
import { forEach, fromPairs, isPlainObject } from "lodash";
import { copy } from "@/framework/clipboard";

axios.defaults.timeout = 60 * 1000; // 默认超时时间

/**
 * 是否相对路径
 * @param url
 */
function isRelativePath(url) {
  return !/^(https?)?:\/\//.test(url);
}

const request = axios.create({
  baseURL: IS_PROD ? API_URL : null,
  transformRequest: [],
  // timeout:5 * 1000,
});

function messageTryCatch(err: any) {
  const { errCode, errMsg, data } = err;
  let title = `[${errCode}] 错误`;
  let message = "";
  if (data) {
    title += "：" + errMsg;
    if (isPlainObject(data)) {
      message += "<ol class='ps-4 text-start'>";
      forEach(data, (msgs, key) => {
        forEach(msgs, msg => {
          message += `<li><b>${key}</b>：<span class='text-danger'>${msg}</span></li>`;
        });
      });
      message += "</ol>";
    } else {
      message = `<span class='text-danger'>${data}</span>`;
    }
  } else {
    message = `<span class='text-danger'>${errMsg}</span>`;
  }

  const instance = Notification.error({
    title: title,
    message: message,
    dangerouslyUseHTMLString: true,
    duration: 0, // 发生错误的话，提示框不自动关闭比较好
  });
  //#region 附加一个复制错误的按钮到提示框上
  const copyInstance = new Vue({
    components: {
      tooltip: Tooltip,
    },
    render(h) {
      return h(
        "tooltip",
        {
          props: {
            placement: "top",
            content: "复制错误信息",
            enterable: false,
          },
        },
        [
          h(
            "div",
            {
              staticClass: "position-absolute bottom-0 start-0 mb-3 ms-3 el-notification__copy",
              on: {
                click: async e => {
                  e.preventDefault && e.preventDefault(); // 阻止默认行为
                  e.returnValue = false; // ie
                  e.stopPropagation && e.stopPropagation(); // 阻止冒泡
                  e.stopImmediatePropagation && e.stopImmediatePropagation();

                  await copy(message, { format: "text/html" });
                  Message({
                    type: "success",
                    message: "复制成功",
                  });
                },
              },
            },
            [h("i", { staticClass: "el-icon-document-copy" })]
          ),
        ]
      );
    },
  }).$mount();
  //#endregion
  // iconElm.innerHTML = "<i class='el-icon-document-copy'></i>";
  instance.$el.append(copyInstance.$el);
}

request.interceptors.request.use(
  async cfg => {
    const langs = getLanguages();
    debugger;

    cfg.headers["Accept-Language"] = langs.join(",");
    const TOKEN_JSON = await OidcGetUser();

    if (TOKEN_JSON) {
      cfg.headers.Authorization = TOKEN_JSON.token_type + " " + TOKEN_JSON.access_token;
    }
    if (isRelativePath(cfg.url) && !IS_PROD) {
      if (!/^\/?proxy/.test(cfg.url)) {
        if (cfg.url[0] === "/") {
          cfg.url = "/proxy" + cfg.url;
        } else {
          cfg.url = "/proxy/" + cfg.url;
        }
      }
    }

    console.group("Axios 请求：", cfg.url);
    console.log("请求头：", cfg.headers);
    console.log("请求体：", cfg.data);
    console.groupEnd();

    return cfg;
  },
  error => Promise.reject(error)
);

let showDialogPromise: Promise<any>;
// 返回数据的拦截器处理
request.interceptors.response.use(
  async res => {
    let { data } = res;
    //! 判断是否 Blob 对象
    if (data instanceof Blob) {
      //! 判断如果获得的Blob 对象是一个json 格式的对象的时候，
      //! 极大可能性是因为在请求服务器Blob 数据时候发生了异常，而由服务端返回的一些错误信息
      //! 所以这种情况下，将blob 对象转换为正常的JSON 对象
      if (data.type === "application/json") {
        const jsonStr = await data.text();
        data = JSON.parse(jsonStr);
      } else {
        return res;
      }
    }
    // 依据返回数据的格式进行二次处理.
    //! 数据也是js 中的object 对象中的一种
    if (data && typeof data === "object" && !Array.isArray(data)) {
      // 当错误码为0 时，表示没有错误
      if (data.errCode === 0) {
        // 成功返回数据时候的处理
        res.data = data.data;
        return res;
      } else if (data.errMsg) {
        if (data.status === 404) {
          let title = "处理失败";
          if (res.config.method === "put") {
            title = "保存失败";
          }
          MessageBox.alert(data.errMsg, title, {
            type: "error",
            center: true,
            showClose: false,
            confirmButtonClass: "el-button--danger",
          });
        } else if (data.status === 400 && data.errMsg) {
          if (data.data) {
            MessageBox.alert(data.errMsg, "校验未通过", {
              type: "error",
              center: true,
              showClose: false,
              confirmButtonClass: "el-button--danger",
            });
          } else {
            MessageBox.alert(`<div class="text-danger">${data.errMsg}</div>`, "校验未通过", {
              type: "error",
              dangerouslyUseHTMLString: true,
              center: true,
              showClose: false,
              confirmButtonClass: "el-button--danger",
            });
          }
        } else {
          debugger;
          messageTryCatch(data);
        }
        // return Promise.reject(data);
        return Promise.reject(data);
      } else {
        // 服务端缺少失败时候的错误信息：errMsg
        return res;
      }
    } else {
      return res;
    }
  },
  async err => {
    // 请求的内部异常的处理
    if (err.name === "AxiosError") {
      const { response } = err;
      if (response && response.status === 413) {
        if (!showDialogPromise) {
          showDialogPromise = MessageBox.alert(
            `<span class='text-danger'>${err.message}</span><br/>请先检查提交的数据是否过大<br />若反复尝试任无法解决问题，请联系管理员检查`,
            `【${err.code}】提交的资源过大`,
            {
              dangerouslyUseHTMLString: true,
              center: true,
              confirmButtonText: "好的👌",
              type: "error",
              showClose: false,
            }
          );
        }
        await showDialogPromise;
        showDialogPromise = null;
      } else if (response && response.status === 500) {
        //! 判断是否已经存在500 的弹窗提示，如果存在，则不创建新的弹窗
        //! 控制到只会显示一次
        if (!showDialogPromise) {
          showDialogPromise = MessageBox.alert(
            `<span class='text-danger'>${err.message}</span><br/>请求服务器时发生了异常，请稍后重试<br />若反复尝试任无法解决问题，请联系管理员检查`,
            `【${err.code}】服务器错误`,
            {
              dangerouslyUseHTMLString: true,
              center: true,
              confirmButtonText: "好的👌",
              type: "error",
              showClose: false,
            }
          );
        }
        await showDialogPromise;
        showDialogPromise = null;
      } else if (response && response.status === 401) {
        // 当请求接口时返回了401 信息，说明身份信息已经失效，需要重新登录，直接跳转到登录页面
        debugger;
        removeUser();
        await signinRedirect();
      } else {
        if (!showDialogPromise) {
          showDialogPromise = MessageBox.alert(`<span class='text-danger'>${err.message}</span>`, `请求错误：${err.code}`, {
            dangerouslyUseHTMLString: true,
            center: true,
            confirmButtonText: "刷新页面",
            type: "error",
          }).then(() => {
            disableAllUnloadMessage();
            showLoading("正在跳转，请稍候");
            localStorage.clear();
            sessionStorage.clear();
            const newUrl = new URL(location.href);
            newUrl.searchParams.delete("ts");
            newUrl.searchParams.append("ts", getCacheId());
            location.href = newUrl.href;
          });
        }
        await showDialogPromise;
        showDialogPromise = null;
      }
    } else if (err.name === "OidcError") {
      debugger;
      if (err.message === "Unauthorized") {
        // 若用户不存在，则可能因为某种原因导致数据身份失效了，出现操作提示
        if (!showDialogPromise) {
          showDialogPromise = MessageBox.alert("登录凭据已失效", "提示", {
            center: true,
            type: "warning",
            confirmButtonText: "前往登录",
            showClose: false,
          });
        }
        await showDialogPromise;
        showDialogPromise = null;
        // 跳转到登录页重新验证身份
        // await signinPopup();
        await signinRedirect();
      }
      debugger;
    } else if (err.name === "CanceledError" && err.message === "canceled") {
      // 当针对请求的接口进行取消请求时候的处理
      console.debug("已取消请求！");
    } else {
      debugger;
      // if (response.status === 500) {
      MessageBox.alert(
        `<span class='text-danger'>${err.message}</span><br />先别急着离开！<br />您可以将下方信息提供给管理员进行分析处理，感谢！`,
        `【${err.code}】未能发现的错误`,
        {
          dangerouslyUseHTMLString: true,
          center: true,
          type: "error",
        }
      );
      // }
    }
    return Promise.reject(err);
  }
);
/**
 * 获取本地路径资源
 * @param url 本地资源url路径
 */
export function getResource(url) {
  const service = axios.create({
    baseURL: PUBLIC_PATH,
  });

  return service.get(url);
}

/**
 * 创建一个可以取消请求的token
 * @returns
 */
export function createCancelToken() {
  return axios.CancelToken.source();
}

// 将 searchDto 转换为 URLSearchParams 的数据格式
function jsonToPairParams(prefix: string, value: any) {
  const urlParams = [];

  if (value) {
    if (Array.isArray(value)) {
      value.forEach((item, index) => {
        const parms = jsonToPairParams(`${prefix}.${index}`, item);
        parms.forEach(item => {
          urlParams.push(item);
        });
      });
    } else if (typeof value === "object") {
      Object.keys(value).forEach(key => {
        const parms = jsonToPairParams(`${prefix}.${key}`, value[key]);
        parms.forEach(item => {
          urlParams.push(item);
        });
      });
    } else {
      urlParams.push([prefix, value]);
    }
  }
  return urlParams;
}

export function jsonToParams(prefix: string, value: any) {
  const pairArrs = jsonToPairParams(prefix, value);
  return fromPairs(pairArrs);
}

export default request;
